package com.icongyou.enterprise.talent_analysis.service.support;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

/**
 * OpenAI客户端测试
 */
@DisplayName("OpenAI客户端测试")
class OpenAIClientTest {

    private OpenAIClient openAIClient;
    private RestTemplate mockRestTemplate;
    private ObjectMapper objectMapper;

    @BeforeEach
    void setUp() {
        openAIClient = new OpenAIClient();
        mockRestTemplate = mock(RestTemplate.class);
        objectMapper = new ObjectMapper();
        
        // 使用反射注入mock的RestTemplate
        ReflectionTestUtils.setField(openAIClient, "restTemplate", mockRestTemplate);
        ReflectionTestUtils.setField(openAIClient, "objectMapper", objectMapper);
        ReflectionTestUtils.setField(openAIClient, "apiKey", "test-api-key");
        ReflectionTestUtils.setField(openAIClient, "apiUrl", "https://api.openai.com/v1/chat/completions");
        ReflectionTestUtils.setField(openAIClient, "model", "gpt-3.5-turbo");
    }

    @Test
    @DisplayName("生成评分标准 - OpenAI成功响应")
    void testGenerateScoringStandard_Success() {
        // Given
        String mockResponse = "{\n" +
            "  \"choices\": [\n" +
            "    {\n" +
            "      \"message\": {\n" +
            "        \"content\": \"{\\\"metrics\\\": [{\\\"metricKey\\\": \\\"avg_score\\\", \\\"weight\\\": 1.0}]}\"\n" +
            "      }\n" +
            "    }\n" +
            "  ]\n" +
            "}";
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenReturn(mockResponse);

        // When
        String result = openAIClient.generateScoringStandard("test prompt");

        // Then
        assertNotNull(result);
        assertTrue(result.contains("metrics"));
        verify(mockRestTemplate).postForObject(anyString(), any(), eq(String.class));
    }

    @Test
    @DisplayName("生成评分标准 - API调用失败")
    void testGenerateScoringStandard_ApiFailure() {
        // Given
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenThrow(new RestClientException("API调用失败"));

        // When & Then
        assertThrows(RuntimeException.class, () -> {
            openAIClient.generateScoringStandard("test prompt");
        });
    }

    @Test
    @DisplayName("推荐数据映射 - 成功")
    void testRecommendMapping_Success() {
        // Given
        String mockResponse = "{\n" +
            "  \"choices\": [\n" +
            "    {\n" +
            "      \"message\": {\n" +
            "        \"content\": \"[\\\"field1\\\", \\\"field2\\\"]\"\n" +
            "      }\n" +
            "    }\n" +
            "  ]\n" +
            "}";
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenReturn(mockResponse);

        // When
        String result = openAIClient.recommendMapping("test prompt");

        // Then
        assertNotNull(result);
        verify(mockRestTemplate).postForObject(anyString(), any(), eq(String.class));
    }

    @Test
    @DisplayName("评估维度 - 成功")
    void testEvaluateDimension_Success() {
        // Given
        String mockResponse = "{\n" +
            "  \"choices\": [\n" +
            "    {\n" +
            "      \"message\": {\n" +
            "        \"content\": \"4.5\"\n" +
            "      }\n" +
            "    }\n" +
            "  ]\n" +
            "}";
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenReturn(mockResponse);

        // When
        String result = openAIClient.evaluateDimension("test prompt");

        // Then
        assertEquals("4.5", result);
        verify(mockRestTemplate).postForObject(anyString(), any(), eq(String.class));
    }

    @Test
    @DisplayName("分析文本 - 成功")
    void testAnalyzeText_Success() {
        // Given
        String mockResponse = "{\n" +
            "  \"choices\": [\n" +
            "    {\n" +
            "      \"message\": {\n" +
            "        \"content\": \"positive\"\n" +
            "      }\n" +
            "    }\n" +
            "  ]\n" +
            "}";
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenReturn(mockResponse);

        // When
        String result = openAIClient.analyzeText("这是一段评语", "sentiment");

        // Then
        assertEquals("positive", result);
        verify(mockRestTemplate).postForObject(anyString(), any(), eq(String.class));
    }

    @Test
    @DisplayName("提取关键词 - 成功")
    void testExtractKeywords_Success() {
        // Given
        List<String> comments = Arrays.asList("评语1", "评语2");
        String mockResponse = "{\n" +
            "  \"choices\": [\n" +
            "    {\n" +
            "      \"message\": {\n" +
            "        \"content\": \"{\\\"关键词1\\\": 5, \\\"关键词2\\\": 3}\"\n" +
            "      }\n" +
            "    }\n" +
            "  ]\n" +
            "}";
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenReturn(mockResponse);

        // When
        String result = openAIClient.extractKeywords(comments);

        // Then
        assertNotNull(result);
        assertTrue(result.contains("关键词"));
        verify(mockRestTemplate).postForObject(anyString(), any(), eq(String.class));
    }

    @Test
    @DisplayName("聊天 - 成功")
    void testChat_Success() {
        // Given
        String mockResponse = "{\n" +
            "  \"choices\": [\n" +
            "    {\n" +
            "      \"message\": {\n" +
            "        \"content\": \"这是AI的回复\"\n" +
            "      }\n" +
            "    }\n" +
            "  ]\n" +
            "}";
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenReturn(mockResponse);

        // When
        String result = openAIClient.chat("Hello");

        // Then
        assertEquals("这是AI的回复", result);
        verify(mockRestTemplate).postForObject(anyString(), any(), eq(String.class));
    }

    @Test
    @DisplayName("通义千问API - 成功响应")
    void testDashScopeApi_Success() {
        // Given
        ReflectionTestUtils.setField(openAIClient, "apiUrl", "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation");
        
        String mockResponse = "{\n" +
            "  \"output\": {\n" +
            "    \"text\": \"通义千问的回复\"\n" +
            "  }\n" +
            "}";
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenReturn(mockResponse);

        // When
        String result = openAIClient.chat("Hello");

        // Then
        assertEquals("通义千问的回复", result);
        verify(mockRestTemplate).postForObject(anyString(), any(), eq(String.class));
    }

    @Test
    @DisplayName("API响应解析异常")
    void testParseResponseFailure() {
        // Given
        String invalidResponse = "invalid json";
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenReturn(invalidResponse);

        // When & Then
        assertThrows(RuntimeException.class, () -> {
            openAIClient.chat("Hello");
        });
    }

    @Test
    @DisplayName("空API Key应抛出异常")
    void testEmptyApiKey() {
        // Given
        ReflectionTestUtils.setField(openAIClient, "apiKey", "");
        String mockResponse = "{\"choices\": [{\"message\": {\"content\": \"test\"}}]}";
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenReturn(mockResponse);

        // When - 即使apiKey为空，也会尝试调用（由API服务器返回401错误）
        // 这里主要测试代码不会因为空apiKey直接崩溃
        assertDoesNotThrow(() -> {
            try {
                openAIClient.chat("Hello");
            } catch (Exception e) {
                // 可能抛出运行时异常，这是预期的
            }
        });
    }

    @Test
    @DisplayName("多次调用使用相同的RestTemplate")
    void testMultipleCallsUseSameRestTemplate() {
        // Given
        String mockResponse = "{\"choices\": [{\"message\": {\"content\": \"test\"}}]}";
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenReturn(mockResponse);

        // When
        openAIClient.chat("prompt1");
        openAIClient.generateScoringStandard("prompt2");
        openAIClient.evaluateDimension("prompt3");

        // Then
        verify(mockRestTemplate, times(3)).postForObject(anyString(), any(), eq(String.class));
    }

    @Test
    @DisplayName("提取关键词 - 构建正确的提示词")
    void testExtractKeywords_CorrectPrompt() {
        // Given
        List<String> comments = Arrays.asList(
            "该学生表现优秀",
            "团队合作能力强"
        );
        String mockResponse = "{\"choices\": [{\"message\": {\"content\": \"{}\"}}]}";
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenReturn(mockResponse);

        // When
        openAIClient.extractKeywords(comments);

        // Then - 验证调用了API（提示词应包含评语内容）
        verify(mockRestTemplate).postForObject(anyString(), any(), eq(String.class));
    }

    @Test
    @DisplayName("不同方法使用不同的maxTokens")
    void testDifferentMaxTokensForDifferentMethods() {
        // Given
        String mockResponse = "{\"choices\": [{\"message\": {\"content\": \"test\"}}]}";
        when(mockRestTemplate.postForObject(anyString(), any(), eq(String.class)))
            .thenReturn(mockResponse);

        // When
        openAIClient.generateScoringStandard("prompt"); // maxTokens=1000
        openAIClient.evaluateDimension("prompt"); // maxTokens=50
        openAIClient.chat("prompt"); // maxTokens=1000

        // Then - 所有调用都应该成功
        verify(mockRestTemplate, times(3)).postForObject(anyString(), any(), eq(String.class));
    }
}
